package com.xinsoft.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xinsoft.common.Response;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.constant.Const;
import com.xinsoft.entity.dto.ApproveDTO;
import com.xinsoft.common.ApprovedParam;
import com.xinsoft.entity.po.*;
import com.xinsoft.mapper.ScmApproveHisMapper;
import com.xinsoft.service.*;
import com.xinsoft.utils.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ApproveServiceImpl implements ApproveService {

    @Resource
    private ScmApproveHisMapper approveHisMapper;
    @Autowired
    private SysApproveFlowService approveFlowService;
    @Autowired
    private SysApproveFlowNodeService approveFlowNodeService;
    @Autowired
    private SysApproveNodeRelService approveNodeRelService;
    @Autowired
    private ScmApproveHisService approveHisService;
    @Autowired
    private ScmUserApproveRefService userApproveRefService;
    @Autowired
    private ScmSaleService saleService;
    @Autowired
    private SysUserRoleService userRoleService;
    @Autowired
    private SysUserService userService;
    @Autowired
    private ScmSaleNoticeService saleNoticeService;
    @Autowired
    private ScmPurchaseService scmPurchaseServices;
    @Autowired
    private ScmPurchasePlanService scmPurchasePlanService;
    @Autowired
    private ScmOutsourcingContractService scmOutsourcingContractService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<?> submitApprove(ApproveDTO approveDTO) {
        Integer sourceId = approveDTO.getSourceId();
        Integer sourceType = approveDTO.getSourceType();
        String sourceTypeName = approveDTO.getSourceTypeName();
        String sourceCode = "";

        List<SysApproveFlow> approveFlowList = approveFlowService.list(Wrappers.lambdaQuery(SysApproveFlow.class)
                .eq(SysApproveFlow::getTabName, sourceTypeName)
                .eq(SysApproveFlow::getFlowStatus, Const.USER_STATUS_NORMAL));
        if (CollectionUtil.isEmpty(approveFlowList) || approveFlowList.size() > 1) {
            throw new BDException(sourceTypeName + "审批流程设置异常，请联系管理员");
        }
        SysApproveFlow flow = approveFlowList.get(0);

        // 更新源单审批状态
        sourceCode = this.updateApproveStatus(sourceId, sourceType, Const.ApproveStatus.SUBMIT);

        // 添加审批节点，提交审批时审批节点顺序为1（num=1）
        this.addApproveNode(flow, sourceId, sourceType, sourceCode, 1);
        return Response.succeed();
    }

    /**
     * 添加审批节点
     *
     * @param flow       审批流程
     * @param sourceId   源单id
     * @param sourceCode 源单code
     * @param num        审批节点顺序
     */
    public void addApproveNode(SysApproveFlow flow, Integer sourceId, Integer sourceType, String sourceCode, Integer num) {
        ScmApproveHis approveHis = new ScmApproveHis();
        List<ScmUserApproveRef> userApproveRefList = new ArrayList<>();

        List<SysApproveFlowNode> flowNodeList = approveFlowNodeService.list(Wrappers.lambdaQuery(SysApproveFlowNode.class).eq(SysApproveFlowNode::getFlowId, flow.getId()));

        SysApproveFlowNode flowNode = approveFlowNodeService.getOne(Wrappers.lambdaQuery(SysApproveFlowNode.class)
                .eq(SysApproveFlowNode::getFlowId, flow.getId())
                .eq(SysApproveFlowNode::getNum, num));
        // 提交审批
        approveHis.setSourceType(sourceType);
        approveHis.setSourceCode(sourceCode);
        approveHis.setSourceId(sourceId);
        approveHis.setFlowId(flow.getId());
        approveHis.setFlowName(flow.getFlowName());
        approveHis.setFlowNodeId(flowNode.getId());
        approveHis.setNodeName(flowNode.getNodeName());
        approveHis.setNum(flowNode.getNum());
        approveHis.setExecutionTimeLimit(flowNode.getExecutionTimeLimit());
        approveHis.setIsCountersign(flowNode.getIsCountersign());
        approveHis.setDoNextNode(flowNodeList.size() > flowNode.getNum() ? 1 : 0);
        approveHis.setDoComplete(0);
        approveHis.setApproveResult(3);
        // 保存审批历史记录
        approveHisService.save(approveHis);

        List<SysApproveNodeRel> nodeRelList = approveNodeRelService.list(Wrappers.lambdaQuery(SysApproveNodeRel.class).eq(SysApproveNodeRel::getNodeId, flowNode.getId()));
        Integer flowType = flowNode.getFlowType();
        List<Integer> resourceIdList = nodeRelList.stream().map(SysApproveNodeRel::getResourceId).collect(Collectors.toList());
        switch (flowType) {
            case 1:
                // 指定用户审批
                List<SysUser> userList1 = userService.listByIds(resourceIdList);
                Map<Integer, SysUser> userMap1 = userList1.stream().collect(Collectors.toMap(SysUser::getId, user -> user, (v1, v2) -> v1));
                userList1.forEach(user -> {
                    ScmUserApproveRef userApproveRef = new ScmUserApproveRef();
                    userApproveRef.setApproveId(approveHis.getId());
                    userApproveRef.setApproveResult(Const.ApproveResult.weichuli);
                    userApproveRef.setApprovePersonId(user.getId());
                    userApproveRef.setDoComplete(0);
                    userApproveRef.setApprovePersonName(userMap1.containsKey(user.getId()) ? userMap1.get(user.getId()).getRealName() : "");
                    userApproveRefList.add(userApproveRef);
                });
                break;
            case 2:
                // 指定角色审批
                List<SysUserRole> userRoleList = userRoleService.list(Wrappers.lambdaQuery(SysUserRole.class).in(SysUserRole::getRoleId, resourceIdList));
                List<Integer> userIdList = userRoleList.stream().map(SysUserRole::getUserId).collect(Collectors.toList());
                List<SysUser> userList2 = userService.listByIds(userIdList);
                Map<Integer, SysUser> userMap2 = userList2.stream().collect(Collectors.toMap(SysUser::getId, user -> user, (v1, v2) -> v1));
                userRoleList.forEach(userRole -> {
                    ScmUserApproveRef userApproveRef = new ScmUserApproveRef();
                    userApproveRef.setApproveId(approveHis.getId());
                    userApproveRef.setApproveResult(Const.ApproveResult.weichuli);
                    userApproveRef.setApprovePersonId(userRole.getUserId());
                    userApproveRef.setDoComplete(0);
                    userApproveRef.setApprovePersonName(userMap2.containsKey(userRole.getUserId()) ? userMap2.get(userRole.getUserId()).getRealName() : "");
                    userApproveRefList.add(userApproveRef);
                });

                break;
            case 3:
                // 指定部门审批
                List<SysUser> userList3 = userService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getDeptId, resourceIdList));
                Map<Integer, SysUser> userMap3 = userList3.stream().collect(Collectors.toMap(SysUser::getId, user -> user, (v1, v2) -> v1));
                userList3.forEach(user -> {
                    ScmUserApproveRef userApproveRef = new ScmUserApproveRef();
                    userApproveRef.setApproveId(approveHis.getId());
                    userApproveRef.setApproveResult(Const.ApproveResult.weichuli);
                    userApproveRef.setApprovePersonId(user.getId());
                    userApproveRef.setDoComplete(0);
                    userApproveRef.setApprovePersonName(userMap3.containsKey(user.getId()) ? userMap3.get(user.getId()).getRealName() : "");
                    userApproveRefList.add(userApproveRef);
                });
                break;
            default:
                // 执行默认操作
        }
        // 保存用户审批关联表
        userApproveRefService.saveBatch(userApproveRefList);
    }

    /**
     * 更新源单审批状态
     *
     * @param sourceId      源单id
     * @param sourceType    源单类型
     * @param approveStatus 审批状态
     * @return {@link String} 源单编码
     */
    public String updateApproveStatus(Integer sourceId, Integer sourceType, Integer approveStatus) {
        String sourceCode = "";
        // 销售订单
        if (Const.ApproveType.XSDD.equals(sourceType)) {
            ScmSale sale = saleService.getById(sourceId);
            sale.setApproveStatus(approveStatus);
            sale.setAuditSign(approveStatus.equals(Const.ApproveStatus.APPROVED) ? Const.AUDIT_STATUS_NORMAL : Const.AUDIT_STATUS_WAIT);
            saleService.updateById(sale);
            sourceCode = sale.getContractCode();
        }
        // 发货通知
        if (Const.ApproveType.FHTZ.equals(sourceType)) {
            ScmSaleNotice saleNotice = saleNoticeService.getById(sourceId);
            saleNotice.setApproveStatus(approveStatus);
            saleNoticeService.updateById(saleNotice);
            sourceCode = saleNotice.getSaleNoticeNo();
        }
        //采购计划
        if (Const.ApproveType.CGJH.equals(sourceType)){
            ScmPurchasePlan scmPurchasePlan = scmPurchasePlanService.getById(sourceId);
            scmPurchasePlan.setApproveStatus(approveStatus);
            scmPurchasePlanService.updateById(scmPurchasePlan);
            sourceCode = scmPurchasePlan.getPurchasePlanCode();
        }
        //采购订单
        if (Const.ApproveType.CGDD.equals(sourceType)){
            ScmPurchase scmPurchase = scmPurchaseServices.getById(sourceId);
            scmPurchase.setApproveStatus(approveStatus);
            scmPurchaseServices.updateById(scmPurchase);
            sourceCode = scmPurchase.getPurchaseCode();
        }
        if (Const.ApproveType.WWHT.equals(sourceType)){
            ScmOutsourcingContract contract = scmOutsourcingContractService.getById(sourceId);
            contract.setApproveStatus(approveStatus);
            contract.setAuditSign(approveStatus.equals(Const.ApproveStatus.APPROVED) ? Const.AUDIT_STATUS_NORMAL : Const.AUDIT_STATUS_WAIT);
            scmOutsourcingContractService.updateById(contract);
            sourceCode = contract.getContractCode();
        }
        return sourceCode;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<?> approved(ApprovedParam param, Integer sourceType) {
        this.checkParam(param); // 参数校验
        Integer id = param.getId();
        Integer result = param.getResult();
        Integer transferId = param.getTransferId();
        String desc = param.getDesc();
        // 节点结束： 更新、新增 审批历史记录表-用户关联审批表，
        ScmApproveHis approveHis = approveHisService.getOne(Wrappers.lambdaQuery(ScmApproveHis.class)
                .eq(ScmApproveHis::getSourceType, sourceType)
                .eq(ScmApproveHis::getSourceId, id)
                .orderByDesc(ScmApproveHis::getNum, ScmApproveHis::getId)
                .last("limit 1"));
        long between = DateUtil.between(approveHis.getCreateTime(), new Date(), DateUnit.HOUR);
        if (ObjectUtil.isNotEmpty(approveHis.getExecutionTimeLimit()) && new Long(approveHis.getExecutionTimeLimit()).compareTo(between) < 0) {
            throw new BDException("超出审批时限：" + approveHis.getExecutionTimeLimit() + "小时!");
        }

        List<ScmUserApproveRef> scmRefList = userApproveRefService.list(Wrappers.lambdaQuery(ScmUserApproveRef.class)
                .eq(ScmUserApproveRef::getApproveId, approveHis.getId())
                .eq(ScmUserApproveRef::getApprovePersonId, TokenUtil.getUserId())
                .eq(ScmUserApproveRef::getDoComplete, 0));
        Map<Integer, ScmUserApproveRef> scmRefListMap = scmRefList.stream().collect(Collectors.toMap(ScmUserApproveRef::getApprovePersonId, item -> item, (v1, v2) -> v1));
        ScmUserApproveRef scmUserApproveRef = scmRefListMap.get(TokenUtil.getUserId());
        if (ObjectUtil.isEmpty(scmRefList) || ObjectUtil.isEmpty(scmUserApproveRef)) {
            throw new BDException("审批失败，不是审批人不能审批！");
        }
        // 1、驳回
        if (Const.ApproveResult.bohui.equals(result)) {
            scmUserApproveRef.setApproveResult(result);
            scmUserApproveRef.setApproveTime(new Date());
            scmUserApproveRef.setDoComplete(1);
            approveHis.setApproveResult(result);
            approveHis.setApproveDesc(desc);
            approveHis.setDoComplete(1);

            // 更新源单审批状态
            this.updateApproveStatus(id, sourceType, Const.ApproveStatus.STAGING);

            scmRefList.forEach(item -> item.setDoComplete(1));
        }
        // 2、转派
        if (Const.ApproveResult.zhuanpai.equals(result)) {
            if (ObjectUtil.isEmpty(transferId)) {
                throw new BDException("未选择转派人！");
            }
            SysUser transferUserDO = userService.getById(transferId);
            scmUserApproveRef.setApproveResult(result);
            scmUserApproveRef.setApproveTime(new Date());
            scmUserApproveRef.setDoComplete(1);
            approveHis.setApproveDesc(desc);
            approveHis.setDoComplete(1);
            approveHis.setApproveResult(Const.ApproveResult.zhuanpai);
            ScmUserApproveRef scmTransferApproveRef = new ScmUserApproveRef();
            scmTransferApproveRef.setApproveId(approveHis.getId());
            scmTransferApproveRef.setApprovePersonId(transferId);
            scmTransferApproveRef.setApprovePersonName(transferUserDO.getRealName());
            scmTransferApproveRef.setApproveResult(Const.ApproveResult.weichuli);
            scmTransferApproveRef.setDoComplete(0);
            userApproveRefService.save(scmTransferApproveRef);
            scmRefList.forEach(item -> item.setDoComplete(1));
        }
        // 3、同意
        if (Const.ApproveResult.tongyi.equals(result)) {
            scmUserApproveRef.setApproveResult(result);
            scmUserApproveRef.setApproveTime(new Date());
            // 当前节点是否结束
            boolean determine = (approveHis.getIsCountersign().equals(1) && scmRefList.size() == 1) || approveHis.getIsCountersign().equals(0);
            // 当前节点未结束
            if (!determine) {
                scmUserApproveRef.setDoComplete(0);
            }
            if (determine) {
                scmUserApproveRef.setDoComplete(1);
                approveHis.setApproveResult(result);
                approveHis.setApproveDesc(desc);
                approveHis.setDoComplete(1);
                scmRefList.forEach(item -> item.setDoComplete(1));
            }
            // 当前节点结束、有下一节点 --> 审批未结束 --> 新增节点历史记录
            if (determine && approveHis.getDoNextNode().equals(1)) {
                // approveNodeAdd(approveHis.getSourceCode(), approveHis.getSourceId(), approveHis.getNum() + 1);
                SysApproveFlow flow = approveFlowService.getById(approveHis.getFlowId());
                this.addApproveNode(flow, approveHis.getSourceId(), sourceType, approveHis.getSourceCode(), approveHis.getNum() + 1);

            }
            // 当前节点结束、无下一节点 --> 审批结束 --> 反写源单状态
            if (determine && !approveHis.getDoNextNode().equals(1)) {
                // 更新源单审批状态
                this.updateApproveStatus(id, sourceType, Const.ApproveStatus.APPROVED);
            }
        }
        approveHisService.updateById(approveHis);
        userApproveRefService.updateById(scmUserApproveRef);
        userApproveRefService.updateBatchById(scmRefList);
        return Response.succeed();
    }

    @Override
    public void checkParam(ApprovedParam param) {
        if (param.getResult().equals(0) && Objects.isNull(param.getDesc())) {
            throw new BDException("请输入审批意见");
        }
        if (param.getResult().equals(2) && Objects.isNull(param.getTransferId())) {
            throw new BDException("被转派人id不能为空");
        }
    }

    /**
     * 审批历史记录
     */
    @Override
    public List<Map<String, Object>> approvalHistory(Integer sourceId, Integer sourceType) {
        List<ScmApproveHis> approveHisList = approveHisService.list(Wrappers.lambdaQuery(ScmApproveHis.class)
                .eq(ScmApproveHis::getSourceId, sourceId)
                .eq(ScmApproveHis::getSourceType, sourceType));
        List<Integer> ids = approveHisList.stream().map(ScmApproveHis::getId).collect(Collectors.toList());
        List<Map<String, Object>> mapList = approveHisMapper.getApprovalHistory(ids);
        return mapList;
    }

}
